﻿using Newtonsoft.Json;
using System.Text;
using Wechat_PublicNumber.Model;

namespace Wechat_PublicNumber.Common
{
    [Injection(DIPattern.Singleton)]
    public class WeChatHttpClinetHelper
    {
        [Autowired]
        private ILog _logger;

        [Autowired]
        private HttpClinetHelper _clinetHelper;

        [Autowired]
        private WechatAccessToken _accessToken;

        /// <summary>
        /// 微信专用Post调用
        /// </summary>
        /// <typeparam name="ResponeModel"></typeparam>
        /// <param name="url"></param>
        /// <param name="body"></param>
        /// <param name="param"></param>
        /// <param name="addAccessToken"></param>
        /// <param name="firstInvoke"></param>
        /// <returns></returns>
        public async Task<ResponeModel> Post<ResponeModel>(string url, object body, string[] param = null, bool addAccessToken = true, bool firstInvoke = true) where ResponeModel : WxBaseRespone
        {
            var newUrl = GetNewUrl(url, param, addAccessToken);
            var respone = await _clinetHelper.JsonPost<ResponeModel>(body, newUrl);
            if (InvokeAgain(respone, newUrl, body) && firstInvoke) return await Post<ResponeModel>(url, body, param, addAccessToken, false);
            else return respone;
        }

        /// <summary>
        /// 微信专用Get调用
        /// </summary>
        /// <typeparam name="ResponeModel"></typeparam>
        /// <param name="url"></param>
        /// <param name="param"></param>
        /// <param name="addAccessToken"></param>
        /// <param name="firstInvoke"></param>
        /// <returns></returns>
        public async Task<ResponeModel> Get<ResponeModel>(string url, string[] param = null, bool addAccessToken = true, bool firstInvoke = true) where ResponeModel : WxBaseRespone
        {
            var newUrl = GetNewUrl(url, param, addAccessToken);
            var respone = await _clinetHelper.JsonGet<ResponeModel>(newUrl);
            if (InvokeAgain(respone, newUrl, null) && firstInvoke) return await Get<ResponeModel>(url, param, addAccessToken, false);
            else return respone;
        }

        /// <summary>
        /// 微信专用UploadMedia调用
        /// </summary>
        /// <typeparam name="ResponeModel"></typeparam>
        /// <param name="url"></param>
        /// <param name="filePath"></param>
        /// <param name="fileName"></param>
        /// <param name="param"></param>
        /// <param name="addAccessToken"></param>
        /// <param name="firstInvoke"></param>
        /// <returns></returns>
        public async Task<ResponeModel> UploadMedia<ResponeModel>(string url, string filePath, string fileName, string[] param = null, bool addAccessToken = true, bool firstInvoke = true) where ResponeModel : WxBaseRespone
        {
            var newUrl = GetNewUrl(url, param, addAccessToken);
            var respone = await _clinetHelper.UploadMedia<ResponeModel>(newUrl, filePath, fileName);
            if (InvokeAgain(respone, newUrl, null) && firstInvoke) return await UploadMedia<ResponeModel>(url, filePath, fileName, param, addAccessToken, false);
            else return respone;
        }

        /// <summary>
        /// 是否需要重新调用本接口
        /// </summary>
        /// <typeparam name="ResponeModel"></typeparam>
        /// <param name="respone"></param>
        /// <param name="url"></param>
        /// <param name="body"></param>
        /// <returns></returns>
        private bool InvokeAgain<ResponeModel>(ResponeModel respone, string url, object body = null) where ResponeModel : WxBaseRespone
        {
            var baseRespone = respone as WxBaseRespone;
            if (baseRespone != null && (baseRespone.errcode == 0 || baseRespone.errcode == 40001))
            {
                if (baseRespone.errcode == 0) return false;
                else if (baseRespone.errcode == 40001)
                {
                    _logger.Debug($"InvokeAgain 40001,url:{url},baseRespone:{JsonConvert.SerializeObject(baseRespone)}", "WeChatHttpClinetHelper");
                    _accessToken.expires_time = DateTime.Now.AddMinutes(-1);
                    return true;
                }
            }
            else
                _logger.Error($"Url：{url}，body：{JsonConvert.SerializeObject(body)}，respone：{JsonConvert.SerializeObject(respone)}，", "WeChatHttpClinetHelper");
            return false;
        }

        /// <summary>
        /// 获取新拼接的url地址
        /// </summary>
        /// <param name="url"></param>
        /// <param name="parm"></param>
        /// <param name="addAccessToken"></param>
        /// <returns></returns>
        private string GetNewUrl(string url, string[] parm, bool addAccessToken = true)
        {
            StringBuilder urlBuilder = new StringBuilder(url);

            if (url.IndexOf("?") == -1) urlBuilder.Append("?");
            else if (!url.EndsWith("&")) urlBuilder.Append("&");

            if (addAccessToken)
                urlBuilder.Append($"access_token={_accessToken.access_token}&");

            if (parm == null || parm.Length <= 0)
                return urlBuilder.ToString().TrimEnd('?').TrimEnd('&');

            if (parm.Length % 2 != 0)
                throw new Exception("parm参数数量不正确");

            for (int i = 0; i < parm.Length / 2; i++)
            {
                var index = i * 2;
                urlBuilder.Append($"{parm[index]}={parm[index + 1]}&");
            }

            return urlBuilder.ToString().TrimEnd('&');
        }
    }
}
